﻿//------------------------------------------------------------------------------
// Copyright © FRA & FV 2014
// All rights reserved
//------------------------------------------------------------------------------
// Binary Serialization SDK
//
// SVN revision information:
//   $Revision: 98 $
//------------------------------------------------------------------------------
using System.CodeDom;
using System.IO;

namespace FRAFV.Binary.Serialization.CodeDom
{
	public static class CodeStatementExtensions
	{
		#region Variable expressions

		public static CodeStatementCollection Variable<TValue>(this CodeStatementCollection code, string name, object value)
		{
			code.Add(new CodeVariableDeclarationStatement(typeof(TValue), name, value.AsExpression()));
			return code;
		}

		public static CodeStatementCollection Variable<TValue>(this CodeStatementCollection code, string name)
		{
			code.Add(new CodeVariableDeclarationStatement(typeof(TValue), name));
			return code;
		}

		public static CodeStatementCollection Variable(this CodeStatementCollection code, string name, object value)
		{
			code.Add(new CodeVariableDeclarationStatement("var", name, value.AsExpression()));
			return code;
		}

		#endregion

		#region Method invoke expressions

		public static CodeStatementCollection BaseMethodInvoke(this CodeStatementCollection code, string method, params object[] args)
		{
			code.Add(Base.MethodInvoke(method, args));
			return code;
		}

		public static CodeStatementCollection StaticMethodInvoke<TObject>(this CodeStatementCollection code, string method, params object[] args)
		{
			code.Add(typeof(TObject).MethodInvoke(method, args));
			return code;
		}

		public static CodeStatementCollection MethodInvoke(this CodeStatementCollection code, CodeExpression target, string method, params object[] args)
		{
			code.Add(target.MethodInvoke(method, args));
			return code;
		}

		public static CodeStatementCollection CreateInvoke(this CodeStatementCollection code, string type, params object[] args)
		{
			code.Add(type.AsType().CreateInvoke(args));
			return code;
		}

		#endregion

		#region Binary operator expressions

		public static CodeStatementCollection Increment(this CodeStatementCollection code, CodeArgumentReferenceExpression arg, object value)
		{
			code.Add(arg.Increment(value));
			return code;
		}

		public static CodeStatementCollection Increment(this CodeStatementCollection code, CodeVariableReferenceExpression arg, object value)
		{
			code.Add(arg.Increment(value));
			return code;
		}

		public static CodeStatementCollection Decrement(this CodeStatementCollection code, CodeArgumentReferenceExpression arg, object value)
		{
			code.Add(arg.Decrement(value));
			return code;
		}

		public static CodeStatementCollection Decrement(this CodeStatementCollection code, CodeVariableReferenceExpression arg, object value)
		{
			code.Add(arg.Decrement(value));
			return code;
		}

		#endregion

		#region Condition expressions

		public static CodeConditionStatement Condition(this CodeStatementCollection code, CodeExpression condition)
		{
			var cond = new CodeConditionStatement(condition);
			code.Add(cond);
			return cond;
		}

		#endregion

		#region Comment expressions

		public static CodeStatementCollection Comment(this CodeStatementCollection code, string text)
		{
			code.Add(new CodeCommentStatement(text));
			return code;
		}

		#endregion

		#region Assign expressions

		public static CodeStatementCollection Assign(this CodeStatementCollection code, CodeExpression left, object right)
		{
			code.Add(new CodeAssignStatement(left, right.AsExpression()));
			return code;
		}

		public static CodeStatementCollection Assign(this CodeStatementCollection code, ClassParser.ClassProperty prop, object value)
		{
			return code.Assign(prop.Name.AsField(), value);
		}

		#endregion

		#region Return expressions

		public static void Return(this CodeStatementCollection code, CodeExpression result)
		{
			code.Add(new CodeMethodReturnStatement(result));
		}

		public static void YieldReturn(this CodeStatementCollection code, CodeExpression result)
		{
			//yield return result;
			var sw = new StringWriter();
			sw.Write("yield return ");
			ClassGenerator.provider.Value.GenerateCodeFromExpression(result, sw, ClassGenerator.options.Value);
			code.Snippet(sw.ToString());
		}

		#endregion

		#region Snippet expressions

		public static CodeStatementCollection Snippet(this CodeStatementCollection code, string text)
		{
			code.Add(new CodeExpressionStatement(text.AsSnippet()));
			return code;
		}

		#endregion

		#region Loop expressions

		public static CodeIterationStatement For(this CodeStatementCollection code, string index, CodeExpression test)
		{
			var loop = new CodeIterationStatement(
				new CodeVariableDeclarationStatement(typeof(int), index, 0.AsExpression()),
				test, new CodeAssignStatement(index.AsVariable(), index.AsVariable().Add(1)));
			code.Add(loop);
			return loop;
		}

		public static CodeIterationStatement For(this CodeStatementCollection code, string item, CodeExpression init, CodeExpression test, CodeExpression next)
		{
			var loop = new CodeIterationStatement(
				new CodeVariableDeclarationStatement("var", item, init),
				test, new CodeAssignStatement(item.AsVariable(), next));
			code.Add(loop);
			return loop;
		}

		public static CodeIterationStatement ForEach(this CodeStatementCollection code, ClassParser.ClassProperty prop, string item)
		{
			//for(var enumerator = ((System.Collections.IEnumerable)Property).GetEnumerator();
			//    enumerator.MoveNext();) { var item = (Type)e.Current; ... }
			var loop = new CodeIterationStatement(
				new CodeVariableDeclarationStatement("var", "enumerator", prop.Name.AsField()
					.Cast<System.Collections.IEnumerable>().MethodInvoke("GetEnumerator")),
				"enumerator".AsVariable().MethodInvoke("MoveNext"), new CodeExpressionStatement("".AsSnippet()));
			loop.Statements.Variable(item, "enumerator".AsVariable().Property("Current").Cast(prop.Type));
			code.Add(loop);
			return loop;
		}

		public static CodeIterationStatement While(this CodeStatementCollection code, CodeExpression test)
		{
			var loop = new CodeIterationStatement(new CodeExpressionStatement("".AsSnippet()), test, new CodeExpressionStatement("".AsSnippet()));
			code.Add(loop);
			return loop;
		}

		public static CodeIterationStatement ForCount(this CodeStatementCollection code, string index, CodeExpression count)
		{
			//var loop = new CodeIterationStatement(
			//	new CodeVariableDeclarationStatement(typeof(int), index, count),
			//	new CodeBinaryOperatorExpression(index.AsVariable(), CodeBinaryOperatorType.GreaterThan, 0.AsExpression()),
			//	index.AsVariable().Decrement(1));
			//code.Add(loop);
			//return loop;
			return code.For(index, new CodeBinaryOperatorExpression(index.AsVariable(),
				CodeBinaryOperatorType.LessThan, count));
		}

		#endregion
	}
}
